import axios from "axios";
import NProgress from "nprogress";
import { lStorage } from "../storage";
import { store } from "@/store";
import router from "@/router";
import { errorCodeType } from "@/utils/http/error-code-type.js";
import { showNotify, showConfirmDialog } from "vant";

import useLoadingStore from "@/store/modules/loadingStore.js";

// 创建一个管理axios的类
export class Interceptors {
  // 请求接口配置 默认空数组 内含 四个字段
  requestQueue = [];
  instance;

  // 初始化实例  相当于生命周期中的 created 函数
  constructor() {
    // 创建一个 axios 实例
    this.instance = axios.create({
      baseURL:
        import.meta.env.VITE_APP_USE_MOCK === "true"
          ? "" // 启用 Mock 时不设置 baseURL
          : import.meta.env.VITE_APP_BASE_API,
      timeout: import.meta.env.VITE_APP_DEFAULT_HTTP_TIMEOUT
    });

    this.init();
  }

  // 初始化
  init() {
    // ========================================================================== 响应拦截器 - 开始 ==========================================================================
    this.instance.interceptors.request.use(
      config => {
        // 请求成功处理
        // NProgress.start(); // 开始加载进度条
        useLoadingStore().show(); // 开启加载动画
        config.duplicateRequestValidationTime =
          import.meta.env.VITE_APP_PREVENT_DUPLICATE_SUBMISSIONS; // 设置防止重复请求时间

        // 添加请求头
        const token = lStorage.get("USER_TOKEN");
        if (token) {
          config.headers["token"] = token;
          config.headers["Authorization"] = token;
        }

        // 防止一个接口在没有响应之前进行重新提交即重复提交验证，默认不校验 duplicateRequestValidation为true时开启
        if (config.url && config.duplicateRequestValidation) {
          this.removeRequestQueue(config); // 移除重复请求的接口
          this.addRequestQueue(config); // 新增最新请求的接口
        }

        return config;
      },
      error => {
        NProgress.done(); // 结束加载进度条
        useLoadingStore().hide(); // 关闭加载动画
        if (error.response?.data) {
          // 结构 code码 msg提示信息
          const { code, msg } = error.response.data;
          // 判断token是否过期 以后端返回的 code 为准
          if (code === 10021) {
            this.handleTokenExpiration(); // 登出事件
          } else {
            showNotify({
              type: "danger",
              message: msg || "系统出错"
            });
          }
        }
        // 请求出错处理
        return Promise.reject(error);
      }
    );
    // ========================================================================== 响应拦截器 - 结束 ============================================================================

    // ========================================================================== 请求拦截器 - 开始 ==========================================================================
    this.instance.interceptors.response.use(
      response => {
        // 接口响应成功处理
        NProgress.done(); // 结束加载进度条
        useLoadingStore().hide(); // 关闭加载动画
        const res = response.data; // 获取响应值

        if (res === "ok" && res.code === undefined) {
          return {
            code: 1
          };
        }

        // token失效
        if (res.code === 10021 || res.code === 401) {
          this.handleTokenExpiration(); // 登出事件
        }

        return response.data;
      },
      error => {
        NProgress.done(); // 结束进度条
        useLoadingStore().hide(); // 关闭加载动画
        // 接口请求失败处理
        let message = error.message;
        // 重复请求
        if (message.includes("Duplicate request")) {
          showNotify({
            type: "danger",
            message: "禁止重复提交",
            duration: 3 * 1000
          });
          return Promise.reject(error);
        }
        // 请求超时
        else if (message.includes("timeout of")) {
          message = "系统接口请求超时";
          this.removeOverTimeRequest();
        } else if (message.includes("400")) {
          return Promise.reject(error.response);
        }
        // 其他错误
        else if (error.response?.status) {
          message = errorCodeType(error.response?.status);
        }

        showNotify({
          type: "danger",
          message,
          duration: 3 * 1000
        });
        return Promise.reject(error);
      }
    );
    // ========================================================================== 请求拦截器 - 结束 ============================================================================
  }

  // 统一处理登出事件
  handleTokenExpiration() {
    return showConfirmDialog({
      title: "提示",
      message: "当前页面已失效，请重新登录"
    })
      .then(() => {
        store.useUserStore().clearUserData();
        setTimeout(() => {
          router.replace("/login");
        }, 100);
      })
      .catch(() => {
        showNotify({
          type: "warning",
          message: "已取消",
          duration: 3 * 1000
        });
      });
  }

  // 对比 对象参数 是否一致
  deepEqual(obj1, obj2) {
    if (obj1 === obj2) return true;
    if (
      typeof obj1 !== "object" ||
      typeof obj2 !== "object" ||
      obj1 == null ||
      obj2 == null
    )
      return false;
    const keys1 = Object.keys(obj1);
    const keys2 = Object.keys(obj2);
    if (keys1.length !== keys2.length) return false;
    for (const key of keys1) {
      if (!keys2.includes(key) || !this.deepEqual(obj1[key], obj2[key]))
        return false;
    }
    return true;
  }

  // 对比 数组参数 是否一致
  isArrayEqual(arr1, arr2) {
    if (arr1.length !== arr2.length) return false;
    const sortedArr1 = [...arr1].sort();
    const sortedArr2 = [...arr2].sort();
    for (let i = 0; i < sortedArr1.length; i++) {
      if (!this.deepEqual(sortedArr1[i], sortedArr2[i])) return false;
    }
    return true;
  }

  // 移除重复请求 只执行最后一次请求
  addRequestQueue(config) {
    const queueItem = {
      url: config.url, // 接口地址
      method: config.method, // 请求方法
      createTime: Date.now(), // 请求创建时间
      params: Array.isArray(config.params)
        ? config.params
        : config.params || {},
      data: Array.isArray(config.data) ? config.data : config.data || {},
      cancel: null // 初始化取消函数
    };

    // 判断是否需要开启重复请求校验
    if (config.duplicateRequestValidation) {
      // 检查队列中是否存在重复请求
      const isDuplicate = this.requestQueue.some(p => {
        return (
          p.url === queueItem.url &&
          p.method === queueItem.method &&
          this.deepEqual(p.params, queueItem.params) &&
          this.deepEqual(p.data, queueItem.data) &&
          Date.now() - p.createTime <=
            (config.duplicateRequestValidationTime || 0)
        );
      });

      if (isDuplicate) {
        // 如果发现重复请求，直接取消
        config.cancelToken = new axios.CancelToken(cancel => {
          cancel("Duplicate request");
        });
        return;
      }
    }

    // 添加新请求到队列
    config.cancelToken = new axios.CancelToken(cancel => {
      queueItem.cancel = cancel;
      this.requestQueue.push(queueItem);
    });
  }

  // 指定时间内只触发一次接口请求
  removeRequestQueue(target) {
    const currentTime = Date.now();
    const validationTime = target.duplicateRequestValidationTime || 0;

    this.requestQueue = this.requestQueue.filter(p => {
      const isExpired = currentTime - p.createTime > validationTime;
      if (isExpired) {
        p.cancel && p.cancel("Request timeout or completed");
      }
      return !isExpired;
    });
  }

  // 移除请求超时接口
  removeOverTimeRequest() {
    const now = Date.now();
    const timeout =
      Number(import.meta.env.VITE_APP_DEFAULT_HTTP_TIMEOUT) || 10000;

    this.requestQueue = this.requestQueue.filter(item => {
      const isTimeout = now - item.createTime > timeout;
      if (isTimeout) {
        item.cancel && item.cancel("Request timeout");
      }
      return !isTimeout;
    });
  }

  // 返回一下
  getInterceptors() {
    return this.instance;
  }
}
